#pragma once
#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>
#include "Lockguard.hpp"
using namespace std;

const int defaultsize = 5;

template <class T>
class Ringqueue
{
    void P(sem_t &sem)
    {
        sem_wait(&sem);
    }
    void V(sem_t &sem)
    {
        sem_post(&sem);
    }

public:
    Ringqueue(int size = defaultsize) : _size(size), _ringqueue(size), _p_step(0), _c_step(0)
    {
        sem_init(&_space_sem, 0, size); // szie是指最开始空间资源为size
        sem_init(&_data_sem, 0, 0);     // 0是指最开始数据资源为0

        pthread_mutex_init(&_p_mutex, nullptr);
        pthread_mutex_init(&_c_mutex, nullptr);
    }
    void Push(const T &in)
    {
        // 生产

        P(_space_sem); // 对空间资源进行减操作，如果_space_sem已经为0，将被阻塞在这里
        {

            // 加锁
            Lockguard lockguard(&_p_mutex);
            // pthread_mutex_lock(&_p_mutex);

            _ringqueue[_p_step] = in; // 将数据资源放到队列中

            _p_step++;        // 生产者向前走
            _p_step %= _size; // 控制为环形队列
            // 解锁
            // pthread_mutex_unlock(&_p_mutex);
        }

        V(_data_sem); // 增加数据资源的值
    }

    void Pop(T *out)
    {
        // 消费
        P(_data_sem); // 对数据资源进行减操作，如果_space_sem已经为0，将被阻塞在这里

        {
            // pthread_mutex_lock(&_c_mutex);
            Lockguard lockguard(&_c_mutex);
            *out = _ringqueue[_c_step]; // 将数据资源取出
            _c_step++;                  // 生产者向前走
            _c_step %= _size;           // 控制为环形队列

            // pthread_mutex_unlock(&_c_mutex);
        }
        V(_space_sem); // 增加空间资源的值
    }

    ~Ringqueue()
    {
        sem_destroy(&_space_sem);
        sem_destroy(&_data_sem);

        pthread_mutex_destroy(&_p_mutex);
        pthread_mutex_destroy(&_c_mutex);
    }

private:
    vector<T> _ringqueue;
    int _size; // 环形队列的大小

    int _p_step; // 生产者在队列的位置
    int _c_step; // 消费者在队列的位置

    sem_t _space_sem; // 空间信号量，生产者关心
    sem_t _data_sem;  // 数据信号量，消费者关心

    // 用锁实现多生产者之间的互斥和多消费者之间的互斥
    pthread_mutex_t _p_mutex; // 生产者的一把锁
    pthread_mutex_t _c_mutex; // 消费者的一把锁
};
